// Copyright (c) 2020 Presto Labs Pte. Ltd.
// Author: xguo

#pragma once

#include <memory>
#include <utility>

#include "coin2/exchange/apollox/api_order/native_rest_async_asio_subscriber.h"
#include "coin2/exchange/apollox/order_v1/parser.h"
#include "coin2/exchange/apollox_futures/api_order/native_rest_async_asio_subscriber.h"
#include "coin2/exchange/apollox_futures/order_v1/parser.h"
#include "coin2/exchange/binance/api_order/native_rest_async_asio_subscriber.h"
#include "coin2/exchange/binance/order_v1/parser.h"
#include "coin2/exchange/binance_futures/api_order/native_rest_async_asio_subscriber.h"
#include "coin2/exchange/binance_futures/order_v1/parser.h"
#include "coin2/exchange/bit/api_order/native_rest_async_asio_subscriber.h"
#include "coin2/exchange/bit/order_v1/parser.h"
#include "coin2/exchange/bitbank/api_order/native_rest_async_asio_subscriber.h"
#include "coin2/exchange/bitbank/order_v1/parser.h"
#include "coin2/exchange/bitflyer_futures/api_order/native_rest_async_asio_subscriber.h"
#include "coin2/exchange/bitflyer_futures/order_v1/parser.h"
#include "coin2/exchange/bitget/api_order/native_rest_async_asio_subscriber.h"
#include "coin2/exchange/bitget/order_v1/parser.h"
#include "coin2/exchange/bitget_futures/api_order/native_rest_async_asio_subscriber.h"
#include "coin2/exchange/bitget_futures/order_v1/parser.h"
#include "coin2/exchange/bithumb/api_order/native_rest_async_asio_subscriber.h"
#include "coin2/exchange/bithumb/order_v2/parser.h"
#include "coin2/exchange/bitmart/api_order/native_rest_async_asio_subscriber.h"
#include "coin2/exchange/bitmart/order_v3/parser.h"
#include "coin2/exchange/bitmex/api_order/native_rest_async_asio_subscriber.h"
#include "coin2/exchange/bitmex/order_v1/parser.h"
#include "coin2/exchange/bitstamp/api_order/native_rest_async_asio_subscriber.h"
#include "coin2/exchange/bitstamp/order_v2/parser.h"
#include "coin2/exchange/bittrex/api_order/native_rest_async_asio_subscriber.h"
#include "coin2/exchange/bittrex/order_v3/parser.h"
#include "coin2/exchange/btcturk/api_order/native_rest_async_asio_subscriber.h"
#include "coin2/exchange/btcturk/order_v1/parser.h"
#include "coin2/exchange/bybit/api_order_v3/native_rest_async_asio_subscriber.h"
#include "coin2/exchange/bybit/order_v3/parser.h"
#include "coin2/exchange/bybit_futures/api_order_v3/native_rest_async_asio_subscriber.h"
#include "coin2/exchange/bybit_futures/order_v3/parser.h"
#include "coin2/exchange/coincheck/api_order/native_rest_async_asio_subscriber.h"
#include "coin2/exchange/coincheck/order_v1/parser.h"
#include "coin2/exchange/coinone/api_order/native_rest_async_asio_subscriber.h"
#include "coin2/exchange/coinone/order_v2/parser.h"
#include "coin2/exchange/crypto/api_order/native_rest_async_asio_subscriber.h"
#include "coin2/exchange/crypto/order_v2/parser.h"
#include "coin2/exchange/crypto_futures/api_order/native_rest_async_asio_subscriber.h"
#include "coin2/exchange/crypto_futures/order_v1/parser.h"
#include "coin2/exchange/crypto_v1/api_order/native_private_client.h"
#include "coin2/exchange/crypto_v1/api_order/native_rest_async_asio_subscriber.h"
#include "coin2/exchange/crypto_v1/order_v1/parser.h"
#include "coin2/exchange/deribit_base/api_order/native_rest_async_asio_subscriber.h"
#include "coin2/exchange/deribit_futures/order_v2/parser.h"
#include "coin2/exchange/deribit_futures/order_v2/parser2.h"
#include "coin2/exchange/deribit_options/order_v2/parser.h"
#include "coin2/exchange/dydx_futures/api_order/native_rest_async_asio_subscriber.h"
#include "coin2/exchange/dydx_futures/order_v3/parser.h"
#include "coin2/exchange/ftx/order_v1/parser.h"
#include "coin2/exchange/ftx_common/api_order/native_rest_async_asio_subscriber.h"
#include "coin2/exchange/ftx_futures/order_v1/parser.h"
#include "coin2/exchange/gateio/api_order/native_rest_async_asio_subscriber.h"
#include "coin2/exchange/gateio/order_v4/parser.h"
#include "coin2/exchange/gateio_futures/api_order/native_rest_async_asio_subscriber.h"
#include "coin2/exchange/gateio_futures/order_v4/parser.h"
#include "coin2/exchange/gdax/api_order/native_rest_async_asio_subscriber.h"
#include "coin2/exchange/gdax/order_v1/parser.h"
#include "coin2/exchange/gopax/api_order/native_rest_async_asio_subscriber.h"
#include "coin2/exchange/gopax/order_v1/parser.h"
#include "coin2/exchange/huobi/api_order/native_rest_async_asio_subscriber.h"
#include "coin2/exchange/huobi/order_v1/parser.h"
#include "coin2/exchange/huobi_futures/api_order/native_rest_async_asio_subscriber.h"
#include "coin2/exchange/huobi_futures/order_v1/parser.h"
#include "coin2/exchange/korbit/api_order/native_rest_async_asio_subscriber.h"
#include "coin2/exchange/korbit/order_v1/parser.h"
#include "coin2/exchange/kraken/api_order/native_rest_async_asio_subscriber.h"
#include "coin2/exchange/kraken/order_v1/parser.h"
#include "coin2/exchange/kucoin/api_order/native_rest_async_asio_subscriber.h"
#include "coin2/exchange/kucoin/order_v1/parser.h"
#include "coin2/exchange/kucoin_futures/api_order/native_rest_async_asio_subscriber.h"
#include "coin2/exchange/kucoin_futures/order_v1/parser.h"
#include "coin2/exchange/lbank/api_order/native_rest_async_asio_subscriber.h"
#include "coin2/exchange/lbank/order_v2/parser.h"
#include "coin2/exchange/lmax_digital/api_order/native_rest_async_asio_subscriber.h"
#include "coin2/exchange/lmax_digital/order_v1/parser.h"
#include "coin2/exchange/maicoin/api_order/native_rest_async_asio_subscriber.h"
#include "coin2/exchange/maicoin/order_v2/parser.h"
#include "coin2/exchange/mercado/api_order/native_rest_async_asio_subscriber.h"
#include "coin2/exchange/mercado/order_v4/parser.h"
#include "coin2/exchange/mexc/api_order_v3/native_rest_async_asio_subscriber.h"
#include "coin2/exchange/mexc/order_v3/parser.h"
#include "coin2/exchange/mexc_futures/api_order/native_rest_async_asio_subscriber.h"
#include "coin2/exchange/mexc_futures/order_v2/parser.h"
#include "coin2/exchange/okex/api_order/native_rest_async_asio_subscriber.h"
#include "coin2/exchange/okex/order_v3/parser.h"
#include "coin2/exchange/okex_futures/api_order/native_rest_async_asio_subscriber.h"
#include "coin2/exchange/okex_futures/order_v3/parser.h"
#include "coin2/exchange/okex_v5/api_order/native_rest_async_asio_subscriber.h"
#include "coin2/exchange/okex_v5/order_v5/parser.h"
#include "coin2/exchange/okex_v5_futures/api_order/native_rest_async_asio_subscriber.h"
#include "coin2/exchange/okex_v5_futures/order_v5/parser.h"
#include "coin2/exchange/phemex/api_order/native_rest_async_asio_subscriber.h"
#include "coin2/exchange/phemex/order_v1/parser.h"
#include "coin2/exchange/phemex_futures/api_order/native_rest_async_asio_subscriber.h"
#include "coin2/exchange/phemex_futures/order_v1/parser.h"
#include "coin2/exchange/prex/api_order/native_rest_async_asio_subscriber.h"
#include "coin2/exchange/prex/order_v1/parser.h"
#include "coin2/exchange/prex_futures/api_order/native_rest_async_asio_subscriber.h"
#include "coin2/exchange/prex_futures/order_v1/parser.h"
#include "coin2/exchange/uniswap/api_order/grpc/grpc_subscriber.h"
#include "coin2/exchange/uniswap/order_v3/parser.h"
#include "coin2/exchange/upbit/api_order/native_rest_async_asio_subscriber.h"
#include "coin2/exchange/upbit/order_v1/parser.h"

namespace coin2::exchange::factory::order {

class OrderSubsystemComponents {
 public:
  void Create(
      const MarketExchangeApi& mea,
      const coin2::exchange::order::OrderSystemConfig& oss_config,
      const coin2::exchange::order::PrivateSubscriberConfig& sub_config,
      coin2::exchange::base::executor::LiveAsyncExecutor* exec,
      base::api_base::NativeHttpAsioDriver* http_driver) {
    using namespace coin::proto;

    if (mea == MarketExchangeApi{Spot, Binance, "v1"} ||
        mea == MarketExchangeApi{Margin, Binance, "v1"}) {
      rest_client_ =
          std::make_unique<BinanceNativePrivateClient>(mea, oss_config.connection_config());
      rest_subscriber_ = std::make_unique<binance::api_order::BinanceRestAsyncAsioSubscriber>(
          rest_client_.get(),
          http_driver,
          sub_config);
      parser_ = std::make_unique<binance::order_v1::BinanceParser>();
      return;
    }

    if (mea == MarketExchangeApi{Futures, Binance, "v1"} ||
        mea == MarketExchangeApi{Futures, Binance, "v1-delivery"}) {
      bool is_delivery;
      if (mea == MarketExchangeApi{Futures, Binance, "v1"}) {
        is_delivery = false;
      } else {
        is_delivery = true;
      }
      rest_client_ =
          std::make_unique<binance_futures::api_order::BinanceFuturesNativePrivateClient>(
              mea,
              oss_config.connection_config(),
              is_delivery);
      rest_subscriber_ =
          std::make_unique<binance_futures::api_order::BinanceFuturesRestAsyncAsioSubscriber>(
              rest_client_.get(),
              http_driver,
              sub_config);
      parser_ = std::make_unique<binance_futures::order_v1::BinanceFuturesParser>();
      return;
    }

    if (mea == MarketExchangeApi{Spot, Bitbank, "v1"}) {
      rest_client_ =
          std::make_unique<BitbankNativePrivateClient>(mea, oss_config.connection_config());
      rest_subscriber_ = std::make_unique<bitbank::api_order::BitbankRestAsyncAsioSubscriber>(
          rest_client_.get(),
          http_driver,
          sub_config);
      parser_ = std::make_unique<bitbank::order_v1::BitbankParser>();

      // set order cache manager
      static_cast<bitbank::order_v1::BitbankParser*>(parser_.get())
          ->SetOrderCacheManager(static_cast<bitbank::api_order::BitbankRestAsyncAsioSubscriber*>(
                                     rest_subscriber_.get())
                                     ->GetMutableOrderManager());
      return;
    }

    if (mea == MarketExchangeApi{Futures, Bitflyer, "v1"}) {
      rest_client_ =
          std::make_unique<BitflyerFuturesNativePrivateClient>(mea, oss_config.connection_config());
      rest_subscriber_ =
          std::make_unique<bitflyer_futures::api_order::BitflyerFuturesRestAsyncAsioSubscriber>(
              rest_client_.get(),
              http_driver,
              sub_config);
      parser_ = std::make_unique<bitflyer_futures::order_v1::BitflyerFuturesParser>();
      return;
    }

    if (mea == MarketExchangeApi{Spot, Bitflyer, "v1"}) {
      rest_client_ =
          std::make_unique<BitflyerFuturesNativePrivateClient>(mea, oss_config.connection_config());
      rest_subscriber_ =
          std::make_unique<bitflyer_futures::api_order::BitflyerFuturesRestAsyncAsioSubscriber>(
              rest_client_.get(),
              http_driver,
              sub_config);
      parser_ = std::make_unique<bitflyer_futures::order_v1::BitflyerFuturesParser>();
      return;
    }

    if (mea == MarketExchangeApi{Spot, Bithumb, "v2"}) {
      rest_client_ =
          std::make_unique<BithumbNativePrivateClient>(mea, oss_config.connection_config());
      rest_subscriber_ = std::make_unique<bithumb::api_order::BithumbRestAsyncAsioSubscriber>(
          rest_client_.get(),
          http_driver,
          sub_config);
      parser_ = std::make_unique<bithumb::order_v2::BithumbParser>();

      // set order cache manager
      static_cast<bithumb::order_v2::BithumbParser*>(parser_.get())
          ->SetOrderCacheManager(static_cast<bithumb::api_order::BithumbRestAsyncAsioSubscriber*>(
                                     rest_subscriber_.get())
                                     ->GetMutableOrderManager());
      return;
    }

    if (mea == MarketExchangeApi{Futures, Bitmex, "v1"}) {
      rest_client_ =
          std::make_unique<BitmexNativePrivateClient>(mea, oss_config.connection_config());
      rest_subscriber_ = std::make_unique<bitmex::api_order::BitmexRestAsyncAsioSubscriber>(
          rest_client_.get(),
          http_driver,
          sub_config);
      parser_ = std::make_unique<bitmex::order_v1::BitmexParser>();
      return;
    }

    if (mea == MarketExchangeApi{Spot, Bitstamp, "v2"}) {
      rest_client_ =
          std::make_unique<BitstampNativePrivateClient>(mea, oss_config.connection_config());
      rest_subscriber_ = std::make_unique<bitstamp::api_order::BitstampRestAsyncAsioSubscriber>(
          rest_client_.get(),
          http_driver,
          sub_config);
      parser_ = std::make_unique<bitstamp::order_v2::BitstampParser>();
      return;
    }

    if (mea == MarketExchangeApi{Spot, Bybit, "v3"}) {
      rest_client_ = std::make_unique<bybit::api_order_v3::BybitNativePrivateClient>(
          mea,
          oss_config.connection_config());
      rest_subscriber_ = std::make_unique<bybit::api_order_v3::BybitRestAsyncAsioSubscriber>(
          rest_client_.get(),
          http_driver,
          sub_config);
      parser_ = std::make_unique<bybit::order_v3::BybitParser>();
      return;
    }

    if (mea == MarketExchangeApi{Futures, Bybit, "v3"} ||
        mea == MarketExchangeApi{Futures, Bybit, "v3-linear"}) {
      rest_client_ = std::make_unique<bybit_futures::api_order_v3::BybitFuturesNativePrivateClient>(
          mea,
          oss_config.connection_config());
      rest_subscriber_ =
          std::make_unique<bybit_futures::api_order_v3::BybitFuturesRestAsyncAsioSubscriber>(
              rest_client_.get(),
              http_driver,
              sub_config);
      parser_ = std::make_unique<bybit_futures::order_v3::BybitFuturesParser>();
      return;
    }

    if (mea == MarketExchangeApi{Spot, Lbank, "v2"}) {
      rest_client_ = std::make_unique<lbank::api_order::LbankNativePrivateClient>(
          mea,
          oss_config.connection_config());
      rest_subscriber_ = std::make_unique<lbank::api_order::LbankRestAsyncAsioSubscriber>(
          rest_client_.get(),
          http_driver,
          sub_config);
      parser_ = std::make_unique<lbank::order_v2::LbankParser>();
      return;
    }

    if (mea == MarketExchangeApi{Spot, Bitmart, "v3"}) {
      rest_client_ = std::make_unique<bitmart::api_order::BitmartNativePrivateClient>(
          mea,
          oss_config.connection_config());
      rest_subscriber_ = std::make_unique<bitmart::api_order::BitmartRestAsyncAsioSubscriber>(
          rest_client_.get(),
          http_driver,
          sub_config);
      parser_ = std::make_unique<bitmart::order_v3::BitmartParser>();
      return;
    }

    if (mea == MarketExchangeApi{Spot, Bit, "v1"}) {
      rest_client_ = std::make_unique<bit::api_order::BitNativePrivateClient>(
          mea,
          oss_config.connection_config());
      rest_subscriber_ = std::make_unique<bit::api_order::BitRestAsyncAsioSubscriber>(
          rest_client_.get(),
          http_driver,
          sub_config);
      parser_ = std::make_unique<bit::order_v1::BitParser>();
      return;
    }

    if (mea == MarketExchangeApi{Spot, Ftx, "v1"} || mea == MarketExchangeApi{Futures, Ftx, "v1"}) {
      rest_client_ = std::make_unique<FtxNativePrivateClient>(mea, oss_config.connection_config());
      rest_subscriber_ = std::make_unique<ftx_common::api_order::FtxRestAsyncAsioSubscriber>(
          rest_client_.get(),
          http_driver,
          sub_config);
      if (mea == MarketExchangeApi{Spot, Ftx, "v1"}) {
        parser_ = std::make_unique<ftx::order_v1::FtxParser>();
      } else {
        parser_ = std::make_unique<ftx_futures::order_v1::FtxFuturesParser>();
      }
      return;
    }

    if (mea == MarketExchangeApi{Spot, Gateio, "v4"}) {
      rest_client_ =
          std::make_unique<GateioNativePrivateClient>(mea, oss_config.connection_config());
      rest_subscriber_ = std::make_unique<gateio::api_order::GateioRestAsyncAsioSubscriber>(
          rest_client_.get(),
          http_driver,
          sub_config);
      parser_ = std::make_unique<gateio::order_v4::GateioParser>();
      return;
    }

    if (mea == MarketExchangeApi{Futures, Gateio, "v4"} ||
        mea == MarketExchangeApi{Futures, Gateio, "v4-delivery"}) {
      bool is_delivery;
      if (mea == MarketExchangeApi{Futures, Gateio, "v4"}) {
        is_delivery = false;
      } else {
        is_delivery = true;
      }
      rest_client_ = std::make_unique<GateioFuturesNativePrivateClient>(
          mea,
          oss_config.connection_config(),
          is_delivery);
      rest_subscriber_ =
          std::make_unique<gateio_futures::api_order::GateioFuturesRestAsyncAsioSubscriber>(
              rest_client_.get(),
              http_driver,
              sub_config);
      parser_ = std::make_unique<gateio_futures::order_v4::GateioFuturesParser>();
      return;
    }

    if (mea == MarketExchangeApi{Spot, Gdax, "v1"}) {
      rest_client_ = std::make_unique<GdaxNativePrivateClient>(oss_config.connection_config());
      rest_subscriber_ = std::make_unique<gdax::api_order::GdaxRestAsyncAsioSubscriber>(
          rest_client_.get(),
          http_driver,
          sub_config);
      parser_ = std::make_unique<gdax::order_v1::GdaxParser>();
      return;
    }

    if (mea == MarketExchangeApi{Spot, Huobi, "v1"} ||
        mea == MarketExchangeApi{Margin, Huobi, "v1"}) {
      rest_client_ = std::make_unique<HuobiNativePrivateClient>(oss_config.connection_config());
      rest_subscriber_ = std::make_unique<huobi::api_order::HuobiRestAsyncAsioSubscriber>(
          rest_client_.get(),
          http_driver,
          sub_config);
      parser_ = std::make_unique<huobi::order_v1::HuobiParser>();
      return;
    }

    if (mea == MarketExchangeApi{Futures, Huobi, "v1"} ||
        mea == MarketExchangeApi{Futures, Huobi, "v1-swap"} ||
        mea == MarketExchangeApi{Futures, Huobi, "v1-linear-swap"}) {
      rest_client_ = std::make_unique<HuobiFuturesNativePrivateClient>(
          oss_config.connection_config(),
          mea.api);
      rest_subscriber_ =
          std::make_unique<huobi_futures::api_order::HuobiFuturesRestAsyncAsioSubscriber>(
              rest_client_.get(),
              http_driver,
              sub_config);
      parser_ = std::make_unique<huobi_futures::order_v1::HuobiFuturesParser>();
      if (oss_config.connection_config().use_cross_mode()) {
        LOG(INFO) << "SetUseCrossMode: True";
        parser_->SetUseCrossMode(true);
      }
      return;
    }

    if (mea == MarketExchangeApi{Spot, Korbit, "v1"}) {
      rest_client_ =
          std::make_unique<KorbitNativePrivateClient>(mea, oss_config.connection_config());
      rest_subscriber_ = std::make_unique<korbit::api_order::KorbitRestAsyncAsioSubscriber>(
          rest_client_.get(),
          http_driver,
          sub_config);
      parser_ = std::make_unique<korbit::order_v1::KorbitParser>();
      return;
    }

    if (mea == MarketExchangeApi{Spot, Kraken, "v1"}) {
      rest_client_ =
          std::make_unique<KrakenNativePrivateClient>(mea, oss_config.connection_config());
      rest_subscriber_ = std::make_unique<kraken::api_order::KrakenRestAsyncAsioSubscriber>(
          rest_client_.get(),
          http_driver,
          sub_config);
      parser_ = std::make_unique<kraken::order_v1::KrakenParser>();
      return;
    }

    if (mea == MarketExchangeApi{Spot, Lmaxdigital, "v1"}) {
      rest_client_ =
          std::make_unique<LmaxdigitalNativePrivateClient>(oss_config.connection_config());
      using lmax_digital::api_order::LmaxdigitalRestAsyncAsioSubscriber;
      rest_subscriber_ = std::make_unique<LmaxdigitalRestAsyncAsioSubscriber>(
          rest_client_.get(),
          http_driver,
          sub_config);
      parser_ = std::make_unique<lmax_digital::order_v1::LmaxdigitalParser>();
      return;
    }

    if (mea == MarketExchangeApi{Spot, Okex, "v3"}) {
      rest_client_ = std::make_unique<OkexNativePrivateClient>(oss_config.connection_config());
      rest_subscriber_ = std::make_unique<okex::api_order::OkexRestAsyncAsioSubscriber>(
          rest_client_.get(),
          http_driver,
          sub_config);
      parser_ = std::make_unique<okex::order_v3::OkexParser>();
      return;
    }

    if (mea == MarketExchangeApi{Futures, Okex, "v3"} ||
        mea == MarketExchangeApi{Futures, Okex, "v3-swap"}) {
      bool is_swap;
      if (mea == MarketExchangeApi{Futures, Okex, "v3"}) {
        is_swap = false;
      } else {
        is_swap = true;
      }
      rest_client_ = std::make_unique<okex_futures::api_order::OkexFuturesNativePrivateClient>(
          oss_config.connection_config(),
          is_swap);
      rest_subscriber_ =
          std::make_unique<okex_futures::api_order::OkexFuturesRestAsyncAsioSubscriber>(
              rest_client_.get(),
              http_driver,
              sub_config);
      parser_ = std::make_unique<okex_futures::order_v3::OkexFuturesParser>();
      return;
    }

    if (mea == MarketExchangeApi{Spot, Okex, "v5"} ||
        mea == MarketExchangeApi{ExWallet, Okex, "v5"}) {
      rest_client_ =
          std::make_unique<OkexV5NativePrivateClient>(mea, oss_config.connection_config());
      rest_subscriber_ = std::make_unique<okex_v5::api_order::OkexV5RestAsyncAsioSubscriber>(
          rest_client_.get(),
          http_driver,
          sub_config);
      parser_ = std::make_unique<okex_v5::order_v5::OkexV5Parser>();
      return;
    }

    if (mea == MarketExchangeApi{Futures, Okex, "v5"} ||
        mea == MarketExchangeApi{Futures, Okex, "v5-swap"}) {
      bool is_swap;
      if (mea == MarketExchangeApi{Futures, Okex, "v5"}) {
        is_swap = false;
      } else {
        is_swap = true;
      }
      rest_client_ = std::make_unique<OkexV5FuturesNativePrivateClient>(
          mea,
          oss_config.connection_config(),
          is_swap);
      rest_subscriber_ =
          std::make_unique<okex_v5_futures::api_order::OkexV5FuturesRestAsyncAsioSubscriber>(
              rest_client_.get(),
              http_driver,
              sub_config);
      parser_ = std::make_unique<okex_v5_futures::order_v5::OkexV5FuturesParser>();
      const auto config = oss_config.connection_config();
      if (config.has_use_cross_mode()) {
        LOG(INFO) << "SetUseCrossMode: " << config.use_cross_mode();
        parser_->SetUseCrossMode(config.use_cross_mode());
      } else {
        LOG(INFO) << "SetUseCrossMode: " << config.use_cross_mode();
        parser_->SetUseCrossMode(true);
      }
      return;
    }

    if (mea == MarketExchangeApi{Futures, Prex, "v1"}) {
      rest_client_ =
          std::make_unique<PrexFuturesNativePrivateClient>(mea, oss_config.connection_config());
      rest_subscriber_ =
          std::make_unique<prex_futures::api_order::PrexFuturesRestAsyncAsioSubscriber>(
              rest_client_.get(),
              http_driver,
              sub_config);
      parser_ = std::make_unique<prex_futures::order_v1::PrexFuturesParser>();
      return;
    }

    if (mea == MarketExchangeApi{Spot, Prex, "v1"}) {
      rest_client_ = std::make_unique<PrexNativePrivateClient>(mea, oss_config.connection_config());
      rest_subscriber_ = std::make_unique<prex::api_order::PrexRestAsyncAsioSubscriber>(
          rest_client_.get(),
          http_driver,
          sub_config);
      parser_ = std::make_unique<prex::order_v1::PrexParser>();
      return;
    }

    if (mea == MarketExchangeApi{Spot, Upbit, "v1"} ||
        mea == MarketExchangeApi{Spot, Upbitid, "v1"} ||
        mea == MarketExchangeApi{Spot, Upbitth, "v1"} ||
        mea == MarketExchangeApi{Spot, Upbitsg, "v1"}) {
      rest_client_ =
          std::make_unique<UpbitNativePrivateClient>(mea, oss_config.connection_config());
      rest_subscriber_ = std::make_unique<upbit::api_order::UpbitRestAsyncAsioSubscriber>(
          rest_client_.get(),
          http_driver,
          sub_config);
      parser_ = std::make_unique<upbit::order_v1::UpbitParser>();

      // set order cache manager
      static_cast<upbit::order_v1::UpbitParser*>(parser_.get())
          ->SetOrderCacheManager(
              static_cast<upbit::api_order::UpbitRestAsyncAsioSubscriber*>(rest_subscriber_.get())
                  ->GetMutableOrderManager());
      return;
    }

    if (mea == MarketExchangeApi{Spot, Coinone, "v2"}) {
      rest_client_ =
          std::make_unique<CoinoneNativePrivateClient>(mea, oss_config.connection_config());
      rest_subscriber_ = std::make_unique<coinone::api_order::CoinoneRestAsyncAsioSubscriber>(
          rest_client_.get(),
          http_driver,
          sub_config);
      parser_ = std::make_unique<coinone::order_v2::CoinoneParser>();
      return;
    }

    if (mea == MarketExchangeApi{Spot, Crypto, "v2"}) {
      rest_client_ =
          std::make_unique<CryptoNativePrivateClient>(mea, oss_config.connection_config());
      rest_subscriber_ = std::make_unique<crypto::api_order::CryptoRestAsyncAsioSubscriber>(
          rest_client_.get(),
          http_driver,
          sub_config);
      parser_ = std::make_unique<crypto::order_v2::CryptoParser>();
      return;
    }

    if (mea == MarketExchangeApi{Spot, Crypto, "v1"}) {
      rest_client_ =
          std::make_unique<CryptoV1NativePrivateClient>(mea, oss_config.connection_config());
      rest_subscriber_ = std::make_unique<crypto_v1::api_order::CryptoRestAsyncAsioSubscriber>(
          rest_client_.get(),
          http_driver,
          sub_config);
      parser_ = std::make_unique<crypto_v1::order_v1::CryptoParser>();
      return;
    }

    if (mea == MarketExchangeApi{Futures, Crypto, "v1"}) {
      rest_client_ =
          std::make_unique<CryptoFuturesNativePrivateClient>(mea, oss_config.connection_config());
      rest_subscriber_ =
          std::make_unique<crypto_futures::api_order::CryptoFuturesRestAsyncAsioSubscriber>(
              rest_client_.get(),
              http_driver,
              sub_config);
      parser_ = std::make_unique<crypto::order_futures::CryptoFuturesParser>();
      return;
    }

    if (mea == MarketExchangeApi{Spot, Gopax, "v1"}) {
      rest_client_ =
          std::make_unique<GopaxNativePrivateClient>(mea, oss_config.connection_config());
      rest_subscriber_ = std::make_unique<gopax::api_order::GopaxRestAsyncAsioSubscriber>(
          rest_client_.get(),
          http_driver,
          sub_config);
      parser_ = std::make_unique<gopax::order_v1::GopaxParser>();
      return;
    }

    if (mea == MarketExchangeApi{Futures, Deribit, "v2"}) {
      rest_client_ =
          std::make_unique<deribit_futures::api_order::DeribitFuturesNativePrivateClient>(
              mea,
              oss_config.connection_config());
      rest_subscriber_ =
          std::make_unique<deribit_futures::api_order::DeribitFuturesRestAsyncAsioSubscriber>(
              rest_client_.get(),
              http_driver,
              sub_config);
#if DISABLE_DERIBIT_FIX_CLIENT2
      parser_ = std::make_unique<deribit_futures::order_v2::DeribitFuturesParser>();
#else
      parser_ = std::make_unique<deribit_futures::order_v2::DeribitFuturesParser2>();
#endif
      return;
    }

    if (mea == MarketExchangeApi{Options, Deribit, "v2"}) {
      rest_client_ =
          std::make_unique<deribit_futures::api_order::DeribitFuturesNativePrivateClient>(
              mea,
              oss_config.connection_config());
      rest_subscriber_ =
          std::make_unique<deribit_futures::api_order::DeribitFuturesRestAsyncAsioSubscriber>(
              rest_client_.get(),
              http_driver,
              sub_config);
      parser_ = std::make_unique<deribit_futures::order_v2::DeribitOptionsParser>();
      return;
    }

    if (mea == MarketExchangeApi{Spot, Phemex, "v1"}) {
      rest_client_ =
          std::make_unique<PhemexNativePrivateClient>(mea, oss_config.connection_config());
      rest_subscriber_ = std::make_unique<phemex::api_order::PhemexRestAsyncAsioSubscriber>(
          rest_client_.get(),
          http_driver,
          sub_config);
      parser_ = std::make_unique<phemex::order_v1::PhemexParser>();
      return;
    }

    if (mea == MarketExchangeApi{Futures, Phemex, "v1"} ||
        mea == MarketExchangeApi{Futures, Phemex, "v1-linear"}) {
      rest_client_ =
          std::make_unique<PhemexFuturesNativePrivateClient>(mea, oss_config.connection_config());
      rest_subscriber_ =
          std::make_unique<phemex_futures::api_order::PhemexFuturesRestAsyncAsioSubscriber>(
              rest_client_.get(),
              http_driver,
              sub_config);
      parser_ = std::make_unique<phemex_futures::order_v1::PhemexFuturesParser>();
      return;
    }

    if (mea == MarketExchangeApi{Futures, Dydx, "v3"}) {
      rest_client_ =
          std::make_unique<DydxV3NativePrivateClient>(mea, oss_config.connection_config());
      rest_subscriber_ = std::make_unique<dydx_futures::api_order::DydxV3RestAsyncAsioSubscriber>(
          rest_client_.get(),
          http_driver,
          sub_config);
      parser_ = std::make_unique<dydx_v3::order_v3::DydxFuturesV3Parser>();
      return;
    }

    if (mea == MarketExchangeApi{Spot, Btcturk, "v1"}) {
      rest_client_ =
          std::make_unique<BtcturkNativePrivateClient>(mea, oss_config.connection_config());
      rest_subscriber_ = std::make_unique<btcturk::api_order::BtcturkRestAsyncAsioSubscriber>(
          rest_client_.get(),
          http_driver,
          sub_config);
      parser_ = std::make_unique<btcturk::order_v1::BtcturkParser>();
      return;
    }

    if (mea == MarketExchangeApi{Spot, Kucoin, "v1"} ||
        mea == MarketExchangeApi{ExWallet, Kucoin, "v1"}) {
      rest_client_ =
          std::make_unique<KucoinNativePrivateClient>(mea, oss_config.connection_config());
      rest_subscriber_ = std::make_unique<kucoin::api_order::KucoinRestAsyncAsioSubscriber>(
          rest_client_.get(),
          http_driver,
          sub_config);
      parser_ = std::make_unique<kucoin::order_v1::KucoinParser>();
      return;
    }

    if (mea == MarketExchangeApi{Futures, Kucoin, "v1"}) {
      rest_client_ =
          std::make_unique<KucoinFuturesNativePrivateClient>(mea, oss_config.connection_config());
      rest_subscriber_ =
          std::make_unique<kucoin_futures::api_order::KucoinFuturesRestAsyncAsioSubscriber>(
              rest_client_.get(),
              http_driver,
              sub_config);
      parser_ = std::make_unique<kucoin_futures::order_v1::KucoinFuturesParser>();
      return;
    }

    if (mea == MarketExchangeApi{Spot, Coincheck, "v1"}) {
      rest_client_ =
          std::make_unique<CoincheckNativePrivateClient>(mea, oss_config.connection_config());
      rest_subscriber_ = std::make_unique<coincheck::api_order::CoincheckRestAsyncAsioSubscriber>(
          rest_client_.get(),
          http_driver,
          sub_config);
      parser_ = std::make_unique<coincheck::order_v1::CoincheckParser>();
      return;
    }

    if (mea == MarketExchangeApi{Futures, Mexc, "v1"} ||
        mea == MarketExchangeApi{Futures, Mexc, "v2"}) {
      rest_client_ = std::make_unique<mexc_futures::api_order::MexcFuturesNativePrivateClient>(
          mea,
          oss_config.connection_config());
      rest_subscriber_ =
          std::make_unique<mexc_futures::api_order::MexcFuturesRestAsyncAsioSubscriber>(
              rest_client_.get(),
              http_driver,
              sub_config);
      parser_ = std::make_unique<mexc_futures::order_v1::MexcFuturesParser>();
      return;
    }

    if (mea == MarketExchangeApi{Spot, Mexc, "v3"}) {
      rest_client_ = std::make_unique<mexc::api_order_v3::MexcNativePrivateClient>(
          mea,
          oss_config.connection_config());
      rest_subscriber_ = std::make_unique<mexc::api_order_v3::MexcRestAsyncAsioSubscriber>(
          rest_client_.get(),
          http_driver,
          sub_config);
      parser_ = std::make_unique<mexc::order_v3::MexcParser>();
      return;
    }

    if (mea == MarketExchangeApi{Spot, Maicoin, "v2"}) {
      rest_client_ = std::make_unique<maicoin::api_order::MaicoinNativePrivateClient>(
          mea,
          oss_config.connection_config());
      rest_subscriber_ = std::make_unique<maicoin::api_order::MaicoinRestAsyncAsioSubscriber>(
          rest_client_.get(),
          http_driver,
          sub_config);
      parser_ = std::make_unique<maicoin::order_v2::MaicoinParser>();
      return;
    }

    if (mea == MarketExchangeApi{Spot, Bittrex, "v3"}) {
      rest_client_ = std::make_unique<bittrex::api_order::BittrexNativePrivateClient>(
          mea,
          oss_config.connection_config());
      rest_subscriber_ = std::make_unique<bittrex::api_order::BittrexRestAsyncAsioSubscriber>(
          rest_client_.get(),
          http_driver,
          sub_config);
      parser_ = std::make_unique<bittrex::order_v3::BittrexParser>();
      return;
    }

    if (mea == MarketExchangeApi{Futures, Bitget, "v1"}) {
      rest_client_ =
          std::make_unique<BitgetFuturesNativePrivateClient>(mea, oss_config.connection_config());
      rest_subscriber_ =
          std::make_unique<bitget_futures::api_order::BitgetFuturesRestAsyncAsioSubscriber>(
              rest_client_.get(),
              http_driver,
              sub_config);
      parser_ = std::make_unique<bitget_futures::order_v1::BitgetFuturesParser>();
      return;
    }

    if (mea == MarketExchangeApi{Spot, Bitget, "v1"}) {
      rest_client_ =
          std::make_unique<coin2::exchange::bitget::api_order::BitgetNativePrivateClient>(
              mea,
              oss_config.connection_config());
      rest_subscriber_ = std::make_unique<bitget::api_order::BitgetRestAsyncAsioSubscriber>(
          rest_client_.get(),
          http_driver,
          sub_config);
      parser_ = std::make_unique<bitget::order_v1::BitgetParser>();
      return;
    }

    //(TODO: qiang) The exchange was trading too little and development was suspended
    // if (mea == MarketExchangeApi{Spot, Apollox, "v1"}) {
    //   rest_client_ =
    //       std::make_unique<ApolloxNativePrivateClient>(mea, oss_config.connection_config());
    //   rest_subscriber_ = std::make_unique<apollox::api_order::ApolloxRestAsyncAsioSubscriber>(
    //       rest_client_.get(),
    //       http_driver,
    //       sub_config);
    //   parser_ = std::make_unique<apollox::order_v1::ApolloxParser>();
    //   return;
    // }

    if (mea == MarketExchangeApi{Futures, Apollox, "v1"}) {
      rest_client_ =
          std::make_unique<apollox_futures::api_order::ApolloxFuturesNativePrivateClient>(
              mea,
              oss_config.connection_config());
      rest_subscriber_ =
          std::make_unique<apollox_futures::api_order::ApolloxFuturesRestAsyncAsioSubscriber>(
              rest_client_.get(),
              http_driver,
              sub_config);
      parser_ = std::make_unique<apollox_futures::order_v1::ApolloxFuturesParser>();
      return;
    }

    if (mea == MarketExchangeApi{Spot, Mercado, "v4"}) {
      rest_client_ =
          std::make_unique<MercadoNativePrivateClient>(mea, oss_config.connection_config());
      rest_subscriber_ = std::make_unique<mercado::api_order::MercadoRestAsyncAsioSubscriber>(
          rest_client_.get(),
          http_driver,
          sub_config);
      parser_ = std::make_unique<mercado::order_v4::MercadoParser>();
      return;
    }

    if (mea == MarketExchangeApi{Spot, Uniswap, "v3"} ||
        mea == MarketExchangeApi{Spot, Uniswap, "v3-arbitrum"}) {
      rest_client_ = std::make_unique<uniswap::api_order::grpc::UniswapGrpcTradeClient>(
          mea,
          oss_config.connection_config(),
          false);
      rest_subscriber_ = std::make_unique<uniswap::api_order::grpc::UniswapGrpcSubscriber>(
          rest_client_.get(),
          http_driver,
          sub_config);
      parser_ = std::make_unique<uniswap::order_v3::UniswapParser>();
      return;
    }

    THROW() << "[OrderSystem] not implemented for " << mea.String();
  }

  auto parser() { return std::move(parser_); }
  auto rest_subscriber() { return std::move(rest_subscriber_); }
  auto rest_client() { return std::move(rest_client_); }

 private:
  std::unique_ptr<coin2::exchange::base::order::BaseParser> parser_;
  std::unique_ptr<coin2::exchange::base::order::RestSubscriber> rest_subscriber_;
  std::unique_ptr<coin2::exchange::base::order::NativePrivateClient> rest_client_;
};

}  // namespace coin2::exchange::factory::order
